<script lang="ts" setup>
  import { nextTick, onMounted, ref, unref } from 'vue';
  // 接收的参数
  const props = defineProps({
    placement: {
      // popover展开方向
      type: String,
      default: 'bottom-center'
    },
    trigger: {
      // 触发popover的方式
      type: String,
      default: 'hover'
    }
  });

  const popoverTitle = ref<any>(null);
  const popoverContent = ref<any>(null);
  const lPopover = ref<any>(null);

  // 如果placement为bottom-center
  const setBottomCenter = (titleDom: any, contentDom: any, arrowDom: any) => {
    const arrowDomTop = arrowDom.offsetHeight / 2;
    const arrowDomLeft = contentDom.offsetWidth / 2 - arrowDomTop;
    const contentTop = titleDom.offsetHeight;
    const contentLeft = contentDom.offsetWidth / 2 - titleDom.offsetWidth / 2;
    contentDom.style.top = `${contentTop}px`;
    contentDom.style.left = `-${contentLeft}px`;
    arrowDom.style.top = `-${arrowDomTop}px`;
    arrowDom.style.left = `${arrowDomLeft}px`;
  };

  // 如果placement为bottom-start
  const setBottomStart = (titleDom: any, contentDom: any, arrowDom: any) => {
    const arrowDomTop = arrowDom.offsetHeight / 2;
    const arrowDomLeft = titleDom.offsetWidth / 2 - arrowDomTop;
    const contentTop = titleDom.offsetHeight;
    contentDom.style.top = `${contentTop}px`;
    arrowDom.style.top = `-${arrowDomTop}px`;
    arrowDom.style.left = `${arrowDomLeft}px`;
  };

  // 如果placement为bottom-end
  const setBottomEnd = (titleDom: any, contentDom: any, arrowDom: any) => {
    const arrowDomTop = arrowDom.offsetHeight / 2;
    const arrowDomRight = titleDom.offsetWidth / 2 - arrowDomTop;
    const contentTop = titleDom.offsetHeight;
    contentDom.style.top = `${contentTop}px`;
    contentDom.style.right = '0px';
    arrowDom.style.top = `-${arrowDomTop}px`;
    arrowDom.style.right = `${arrowDomRight}px`;
  };

  // 如果placement为top-start
  const setTopStart = (titleDom: any, contentDom: any, arrowDom: any) => {
    const arrowDomBottom = arrowDom.offsetHeight / 2;
    const arrowDomLeft = titleDom.offsetWidth / 2 - arrowDomBottom;
    const contentBottom = titleDom.offsetHeight;
    contentDom.style.bottom = `${contentBottom}px`;
    arrowDom.style.transform = 'rotate(180deg)';
    arrowDom.style.bottom = `-${arrowDomBottom}px`;
    arrowDom.style.left = `${arrowDomLeft}px`;
  };

  // 如果placement为top-center
  const setTopCenter = (titleDom: any, contentDom: any, arrowDom: any) => {
    const arrowDomBottom = arrowDom.offsetHeight / 2;
    const arrowDomLeft = contentDom.offsetWidth / 2 - arrowDomBottom;
    const contentBottom = titleDom.offsetHeight;
    const contentLeft = contentDom.offsetWidth / 2 - titleDom.offsetWidth / 2;
    contentDom.style.bottom = `${contentBottom}px`;
    contentDom.style.left = `-${contentLeft}px`;
    arrowDom.style.transform = 'rotate(180deg)';
    arrowDom.style.bottom = `-${arrowDomBottom}px`;
    arrowDom.style.left = `${arrowDomLeft}px`;
  };

  // 如果placement为top-end
  const setTopEnd = (titleDom: any, contentDom: any, arrowDom: any) => {
    const arrowDomBottom = arrowDom.offsetHeight / 2;
    const arrowDomRight = titleDom.offsetWidth / 2 - arrowDomBottom;
    const contentBottom = titleDom.offsetHeight;
    contentDom.style.bottom = `${contentBottom}px`;
    contentDom.style.right = '0px';
    arrowDom.style.transform = 'rotate(180deg)';
    arrowDom.style.bottom = `-${arrowDomBottom}px`;
    arrowDom.style.right = `${arrowDomRight}px`;
  };

  // 如果placement为left-center
  const setLeftCenter = (titleDom: any, contentDom: any, arrowDom: any) => {
    const arrowDomRight = arrowDom.offsetHeight / 2;
    const arrowDomTop = contentDom.offsetHeight / 2 - arrowDomRight;
    const contentDomLeft = contentDom.offsetWidth + arrowDomRight;
    const contentDomTop = contentDom.offsetHeight / 2;
    contentDom.style.left = `-${contentDomLeft}px`;
    contentDom.style.top = `-${contentDomTop}px`;
    arrowDom.style.transform = 'rotate(90deg)';
    arrowDom.style.right = `-${arrowDomRight}px`;
    arrowDom.style.top = `${arrowDomTop}px`;
  };

  // 如果placement为left-start
  const setLeftStart = (titleDom: any, contentDom: any, arrowDom: any) => {
    const arrowDomRight = arrowDom.offsetHeight / 2;
    const arrowDomTop = titleDom.offsetHeight / 2 - arrowDomRight;
    const contentDomLeft = contentDom.offsetWidth + arrowDomRight;
    const contentDomTop = titleDom.offsetHeight / 2;
    contentDom.style.left = `-${contentDomLeft}px`;
    contentDom.style.top = `-${contentDomTop}px`;
    arrowDom.style.transform = 'rotate(90deg)';
    arrowDom.style.right = `-${arrowDomRight}px`;
    arrowDom.style.top = `${arrowDomTop}px`;
  };

  // 如果placement为left-end
  const setLeftEnd = (titleDom: any, contentDom: any, arrowDom: any) => {
    const arrowDomRight = arrowDom.offsetHeight / 2;
    const arrowDomBottom = titleDom.offsetHeight / 2 - arrowDomRight;
    const contentDomLeft = contentDom.offsetWidth + arrowDomRight;
    const contentDomTop = contentDom.offsetHeight - titleDom.offsetHeight / 2;
    contentDom.style.left = `-${contentDomLeft}px`;
    contentDom.style.top = `-${contentDomTop}px`;
    arrowDom.style.transform = 'rotate(90deg)';
    arrowDom.style.right = `-${arrowDomRight}px`;
    arrowDom.style.bottom = `${arrowDomBottom}px`;
  };
  // 如果placement为right-start
  const setRightStart = (titleDom: any, contentDom: any, arrowDom: any) => {
    const arrowDomleft = arrowDom.offsetHeight / 2;
    const arrowDomTop = titleDom.offsetHeight / 2 - arrowDomleft;
    const contentDomRight = contentDom.offsetWidth + arrowDomleft;
    const contentDomTop = titleDom.offsetHeight / 2;
    contentDom.style.right = `-${contentDomRight}px`;
    contentDom.style.top = `-${contentDomTop}px`;
    arrowDom.style.transform = 'rotate(-90deg)';
    arrowDom.style.left = `-${arrowDomleft}px`;
    arrowDom.style.top = `${arrowDomTop}px`;
  };

  // 如果placement为right-center
  const setRightCenter = (titleDom: any, contentDom: any, arrowDom: any) => {
    const arrowDomLeft = arrowDom.offsetHeight / 2;
    const arrowDomTop = contentDom.offsetHeight / 2 - arrowDomLeft;
    const contentDomRight = contentDom.offsetWidth + arrowDomLeft;
    const contentDomTop = contentDom.offsetHeight / 2;
    contentDom.style.right = `-${contentDomRight}px`;
    contentDom.style.top = `-${contentDomTop}px`;
    arrowDom.style.transform = 'rotate(-90deg)';
    arrowDom.style.left = `-${arrowDomLeft}px`;
    arrowDom.style.top = `${arrowDomTop}px`;
  };

  // 如果placement为right-end
  const setRightEnd = (titleDom: any, contentDom: any, arrowDom: any) => {
    const arrowDomLeft = arrowDom.offsetHeight / 2;
    const arrowDomBottom = titleDom.offsetHeight / 2 - arrowDomLeft;
    const contentDomRight = contentDom.offsetWidth + arrowDomLeft;
    const contentDomTop = contentDom.offsetHeight - titleDom.offsetHeight / 2;
    contentDom.style.right = `-${contentDomRight}px`;
    contentDom.style.top = `-${contentDomTop}px`;
    arrowDom.style.transform = 'rotate(-90deg)';
    arrowDom.style.left = `-${arrowDomLeft}px`;
    arrowDom.style.bottom = `${arrowDomBottom}px`;
  };

  // 控制popover显示隐藏
  const popoverShow = ref<boolean>(false);
  // 关闭popover的定时器
  let closeTimer = null;

  // hover模式显示隐藏
  const initPopover = () => {
    if (closeTimer) {
      clearTimeout(closeTimer);
      closeTimer = null;
    }
    popoverShow.value = !popoverShow.value;
    nextTick(() => {
      const titleDom = popoverTitle.value;
      const contentDom = popoverContent.value;
      const arrowDom = contentDom.querySelectorAll('.l-popover__arrow')[0];
      switch (props.placement) {
        case 'bottom-center':
          setBottomCenter(titleDom, contentDom, arrowDom);
          break;
        case 'bottom-start':
          setBottomStart(titleDom, contentDom, arrowDom);
          break;
        case 'bottom-end':
          setBottomEnd(titleDom, contentDom, arrowDom);
          break;
        case 'top-start':
          setTopStart(titleDom, contentDom, arrowDom);
          break;
        case 'top-center':
          setTopCenter(titleDom, contentDom, arrowDom);
          break;
        case 'top-end':
          setTopEnd(titleDom, contentDom, arrowDom);
          break;
        case 'left-center':
          setLeftCenter(titleDom, contentDom, arrowDom);
          break;
        case 'left-start':
          setLeftStart(titleDom, contentDom, arrowDom);
          break;
        case 'left-end':
          setLeftEnd(titleDom, contentDom, arrowDom);
          break;
        case 'right-start':
          setRightStart(titleDom, contentDom, arrowDom);
          break;
        case 'right-center':
          setRightCenter(titleDom, contentDom, arrowDom);
          break;
        case 'right-end':
          setRightEnd(titleDom, contentDom, arrowDom);
      }
      if (['click', 'contextmenu'].includes(props.trigger)) {
        document.addEventListener('click', clickCallback);
      }
    });
  };

  // 监控点击的callback
  const clickCallback = (e) => {
    if (!unref(lPopover).contains(e.target)) {
      removePopover();
      document.removeEventListener('click', clickCallback);
    }
  };

  const removePopover = () => {
    if (props.trigger === 'hover'){
      closeTimer = setTimeout(() => {
        popoverShow.value = false;
        clearTimeout(closeTimer);
        closeTimer = null;
      }, 300);
    }else {
      popoverShow.value = false;
    }
  };
</script>

<template>
  <div
    class="l-popover"
    @mouseenter="props.trigger === 'hover' ? initPopover() : () => {}"
    @mouseleave="props.trigger === 'hover' ? removePopover() : () => {}"
    @click.stop="props.trigger === 'click' ? initPopover() : () => {}"
    @mousedown="props.trigger === 'focus' ? initPopover() : () => {}"
    @mouseup="props.trigger === 'focus' ? removePopover() : () => {}"
    @contextmenu.prevent.stop="props.trigger === 'contextmenu' ? initPopover($event) : () => {}"
    ref="lPopover">
    <div ref="popoverTitle">
      <slot name="reference"></slot>
    </div>
    <div
      v-if="popoverShow"
      ref="popoverContent"
      class="l-popover__content">
      <span class="l-popover__arrow"></span>
      <slot></slot>
    </div>
  </div>
</template>

<style lang="less" scoped>
  .l-popover {
    position: relative;

    .l-popover__content {
      overflow-wrap: break-word;
      box-sizing: border-box;
      padding: 12px;
      position: fixed;
      box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.12);
      background: #ffffff;
      border-radius: 4px;
      border: 1px solid #e4e7ed;
      margin: 10px 0;
      z-index:2000;

      .l-popover__arrow {
        position: absolute;
        width: 10px;
        height: 10px;

        &::before {
          position: absolute;
          width: 10px;
          height: 10px;
          background: #ffffff;
          content: ' ';
          transform: rotate(45deg);
          box-sizing: border-box;
          border-top: 1px solid #e4e7ed;
          border-left: 1px solid #e4e7ed;
          box-shadow: -12px -12px 12px rgba(0, 0, 0, 0.12);
        }
      }
    }
  }
</style>
